﻿using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;

using Caliburn.Micro;

using Cooking.Client.Commanding;
using Cooking.Client.Querying;
using Cooking.Client.Services;
using Cooking.Client.ViewModels.Coroutines;

namespace Cooking.Client.ViewModels
{
    public class SearchViewModel : Screen
    {
        #region Private Definition

        private string partialTitle;

        private string partialDescription;

        private double minimumRating;
        private IEnumerable<Recipe> recipes = new Recipe[0];
        private readonly ICommandAgent commandAgent;
        private readonly IApplicationController applicationController;
        private const int MaxRating = 5;

        #endregion

        public SearchViewModel(ICommandAgent commandAgent, IApplicationController applicationController)
        {
            this.commandAgent = commandAgent;
            this.applicationController = applicationController;
        }

        /// <summary>
        /// Called when initializing.
        /// </summary>
        protected override void OnInitialize()
        {
            MinimumRating = 0;
            PartialDescription = "";
            PartialTitle = "";
        }

        public string PartialTitle
        {
            get { return partialTitle; }
            set
            {
                partialTitle = value;
                NotifyOfPropertyChange(() => PartialTitle);
            }
        }

        public string PartialDescription
        {
            get { return partialDescription; }
            set
            {
                partialDescription = value;
                NotifyOfPropertyChange(() => PartialDescription);
            }
        }

        public double MinimumRating
        {
            get { return minimumRating; }
            set
            {
                minimumRating = value;
                NotifyOfPropertyChange(() => MinimumRating);
            }
        }

        public IEnumerable<Recipe> Recipes
        {
            get { return recipes; }
            private set
            {
                UntrackRecipeChanges();

                recipes = value;
                NotifyOfPropertyChange(() => Recipes);
                TrackRecipeChanges();
            }
        }

        private void TrackRecipeChanges()
        {
            foreach (var recipe in recipes)
            {
                recipe.PropertyChanged += OnRecipePropertyChanged;
            }
        }

        private void UntrackRecipeChanges()
        {
            foreach (var recipe in recipes)
            {
                recipe.PropertyChanged -= OnRecipePropertyChanged;
            }
        }

        private void OnRecipePropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            var recipe = (Recipe)sender;

            if (e.PropertyName == "Rating")
            {
                commandAgent.Send(new RateRecipeCommand
                {
                    Id = recipe.Id,
                    Version = recipe.Version,
                    Rating = recipe.Rating.Value
                });
            }
        }

        private void OnCommandsSent(object sender, CommandsSentEventArgs e)
        {
            if (e.Commands.Any(c => c is AddNewRecipeCommand))
            {
                // If a new recipe was added, force reloading the recipes from the server.
                FindRecipes();
            }
        }

        public IEnumerable<IResult> FindRecipes()
        {
            var coroutine = new FindRecipesCoroutine
            {
                PartialTitle = partialTitle,
                PartialDescription = partialDescription,
                MinimumRating = (int)(minimumRating * MaxRating)
            };

            yield return coroutine;

            Recipes = coroutine.Recipes;
        }

        public void AddNewRecipe()
        {
            applicationController.ShowRecipeAddingDialog();
        }
    }
}